React Router v6
快速复习
- BrowerRouter
- NavLink vs Link (可以传递参数)
- Routes && Route
- useNavigate 强制路由跳转
- Link && Navigate && useNavigate 通过 state 传递状态,通过 useLocation 接收
- 通过 useParams 接收 URL 参数
一、概述
如何安装
pnpm add react-router-dom@6
概念
- react-router:为 React 应用提供了路由的核心功能;
- react-router-dom:基于 react-router,加入了在浏览器运行环境下的一些功能。
二、基本使用
BrowserRouter
要想在 React 应用中使用 React Router,就需要在 React 项目的根文件(index.tsx)中导入 Router 组件
import { StrictMode } from "react";
import * as ReactDOMClient from "react-dom/client";
import { BrowserRouter } from "react-router-dom";
import App from "./App";
const rootElement = document.getElementById("root");
const root = ReactDOMClient.createRoot(rootElement);
root.render(
《StrictMode》
《BrowserRouter》
《App /》
《/BrowserRouter》
《/StrictMode》
)
BrowserRouter 是最常用的路由方式,即浏览器路由。官方文档也建议将 BrowserRouter 组件用于 Web 应用程序。除了这种方式,React Router 还支持其他几种路由方式:
- HashRouter:在路径前加入#成为一个哈希值,Hash 模式的好处是不会因为刷新页面而找不到对应路径;
- MemoryRouter:不存储 history,路由过程保存在内存中,适用于 React Native 这种非浏览器环境;
- NativeRouter:配合 React Native 使用,多用于移动端;
- StaticRouter:主要用于服务端渲染时。
NavLink
NavLink 组件,它是一个导航链接组件,类似于 HTML 中的《a》标签。NavLink 组件使用 to 来指定需要跳转的链接,在TSX中代码如下:
《NavLink to="product"》产品《/NavLink》
NavLink 是存在 active 状态的,所以可以为active 状态和非active 状态的导航链接添加样式:
import { NavLink } from "react-router-dom";
import "./styles.css";
export default function App() {
return (
《div className="App"》
《header》
《h1》Hello World《/h1》
《/header》
《nav》
《NavLink
to=""
className={({ isActive }) =》 isActive ? "nav-active" : void 0}
》
首页
《/NavLink》
《NavLink to="product"》产品《/NavLink》
《NavLink to="about"》关于《/NavLink》
《/nav》
《/div》
);
}```
### Link🌟
Link 组件与 NavLink 组件非常相似,唯一的区别就是 NavLink 存在 active 状态,而 Link 没有。
如果需要对 Link 进行更多控制,也可以传递给 to 一个对象,在这个对象中,可以通过 search 属性来添加查询字符串或通过 hash 属性来传递 hash值,例如:
```javascript
import { Link } from "react-router-dom";
import "./styles.css";
export default function Settings() {
return (
《div className="settings"》
《header》
《h1》Hello World《/h1》
《Link
to={{
pathname: "/settings",
search: "?sort=date",
hash: "#hash"
}}
》
设置
《/Link》
《/header》
《/div》
);
}
此时路由就变成了 /settings?sort=date#hash
Routes
在 Routes 组件中使用 Route 组件来定义所有路由。该组件接受两个 props:
- path:页面 URL 应导航到的路径,类似于 NavLink 组件的 to;
- element:页面导航到该路由时加载的元素。
import { NavLink, Routes, Route } from "react-router-dom";
import Product from "./Product";
import About from "./About";
import Home from "./Home";
import Error from "./Error";
import "./styles.css";
export default function App() {
return (
《div className="App"》
《header》
《h1》Hello World《/h1》
《/header》
《nav》
《NavLink to=""》首页《/NavLink》
《NavLink to="product"》产品《/NavLink》
《NavLink to="about"》关于《/NavLink》
《/nav》
《Routes》
《Route path="/" element={《Home /》} /》
《Route path="/product" element={《Product /》} /》
《Route path="/about" element={《About /》} /》
《Route path="*" element={《Error /》} /》
《/Routes》
《/div》
);
}
路由顺序
在 React Router v6 以前,我们必须按照一定的顺序来定义路由,以获得准确的渲染。在 v6 及之后的版本中,路由定义的顺序无关紧要。
v5中,/product/new 会匹配到 Product 组件
《Switch》
《Route path="/product/:id" component={Product} /》
《Route path="/product/new" component={NewProduct} /》
《/Switch》
v6 中,将 《Switch》 组件替换为了 《Routes》 组件。/products/new将匹配这两个路由,但只会渲染NewProduct组件,因为它是更具体的匹配:
《Routes》
《Route path="/product/:id" element={《Product /》} /》
《Route path="/product/new" element={《NewProduct /》} /》
《/Routes》
三、编程式导航
React Router 提供了两种不同的编程式导航方式:
- 声明式导航组件:《Navigate》 组件
- 命令式导航方法:useNavigate Hook
可以使用这两种编程的方式来跳转到指定的路由,也可以实现路由的重定向,比如在浏览器的地址栏输入一个 URL 并进行跳转时,如果应用中没有定义该路由,就跳转到应用的首页。
Navigate
和 Navlink 类似,Navigate 组件中通过 to props 来指定要跳转的路径。
import { NavLink, Routes, Route, Navigate } from "react-router-dom";
import Product from "./Product";
import About from "./About";
import Home from "./Home";
import "./styles.css";
export default function App() {
return (
《div className="App"》
《header》
《h1》Hello World《/h1》
《/header》
《nav》
《NavLink to=""》首页《/NavLink》
《NavLink to="product"》产品《/NavLink》
《NavLink to="about"》关于《/NavLink》
《/nav》
《Routes》
《Route path="/" element={《Home /》} /》
《Route path="product" element={《Product /》} /》
《Route path="about" element={《About /》} /》
《Route path="*" element={《Navigate to="/" /》} /》 // 看这里
《/Routes》
《/div》
);
}```
这样,当在浏览器地址栏输入一个未定义的路由时,就会跳转到首页。
### useNavigate🌟
1. 导入 Hook
2. 创建实例
3. 在函数中进行使用
import { useNavigate } from 'react-router-dom
function Register () { const navigate = useNavigate()
return ( 《div》 《Form afterSubmit={() =》 navigate('/')} /》 // 提交完表单之后,跳转到主页 《/div》 ) }
## 四、通过路由传递状态
在 react-router-dom 中可以通过以下三种方式来传递状态,它们的传递方式有区分:
- 使用 Link 组件
- 使用 Navigate 组件
- 使用 useNavigate 钩子
但它们在页面中的获取方式相同,都是通过 **useLocation** 钩子来**获取状态**
### Link && useLocation
Link 组件通过 state props 来将数据从产品页面传递到主页
`《Link to="/" state={"From Product"}》返回《/Link》`
使用一个名为 **useLocation** 的钩子来获取数据
import { useLocation } from "react-router-dom"; // 1.导入 Hook import "./styles.css";
export default function Settings() { let location = useLocation(); // 2.定义实例 return ( 《div className="App"》 《header》首页《/header》 《p》{location.state}《/p》 // 3.页面中使用 《/div》 ); }
### Navigate
Navigate 组件也是通过state属性传递状态, 在页面中也是通过useLocation获取状态
`《Route path="/about" element={《Navigate to="/" state={"From About"} /》} /》`
### useNavigate
使用useNavigate钩子创建的navigate函数有两个参数
第一个是 跳转路由, 第二个是包含状态的对象
```javascript
import { useNavigate } from 'react-router-dom
function Register () {
const navigate = useNavigate()
return (
《div》
《Form afterSubmit={() =》 navigate('/', { state: "From the About Page"})} /》 // 包含state状态的对象
《/div》
)
}
在首页中仍然是使用 useLocation 钩子来获取状态值
五、动态路由
声明一个带有 keyword 占位符的路由即可。对于上面的例子,只需要将 Route 组件的 path props 声明为这样
《Route path="/wiki/:keyword" element={《Wiki /》} /》
如何在组件中访问 URL 中的动态部分呢 -》 使用 useParams 钩子
import React from 'react'
import {useParams} from 'react-router';
function Wiki() {
const { keyword } = useParams()
return (
《div》{ keyword }《/div》
)
}
六、嵌套路由
使用 Outlet 配置嵌套路由
固定 navbar, 更换 main
const Layout = () =》 {
return (
《》
《Navbar /》
《Outlet /》
《Footer /》
《/》
);
};
const router = createBrowserRouter([
{
path: "/",
element: 《Layout /》,
children: [
{
path: "/",
element: 《Home /》,
},
{
path: "/post/:id",
element: 《Single /》,
},
{
path: "/write",
element: 《Write /》,
},
],
},
{
path: "/register",
element: 《Register /》,
},
{
path: "/login",
element: 《Login /》,
},
]);
```
### 展示 messages
```javascript
function App() {
const router = createBrowserRouter([
{
path: "/",
element: 《Home /》,
},
{
path: "/messages",
element: 《Messages /》,
children: [
{
path: ':id',
element: 《MessagesDetails /》
}
]
},
]);
return (
《div className="App"》
《RouterProvider router={router} /》
《/div》
);
}
```
这里
```javascript
import { Outlet } from "react-router-dom";
function Messages() {
return (
《div》
《Conversations /》
《Outlet /》 // 路由为messgaes/id时,会在此渲染 MessagesDetails 组件
《/div》
);
}
```
## 七、查询参数
React Router 提供了一个自定义的 useSearchParams Hook,它是基于 URLSearchParams 进行的封装。useSearchParams 返回一个数组,该数组第一个元素是 URLSearchParams 的实例,第二个元素是更新查询参数的一个方法。
`import { useSearchParams } from 'react-router-dom'
const Results = () =》 {
const [searchParams, setSearchParams] = useSearchParams();
const q = searchParams.get('q')
const src = searchParams.get('src')
const f = searchParams.get('f')
return (
// ...
)
}`
如果需要更新查询字符串,可以使用 setSearchParams,向它传递一个对象,该对象的key/value 对将作为 &key=value 添加到 url:
`const Results = () =》 {
const [searchParams, setSearchParams] = useSearchParams();
const q = searchParams.get('q')
const src = searchParams.get('src')
const f = searchParams.get('f')
const updateOrder = (sort) =》 {
setSearchParams({ sort })
}
return (
...
)
}`
## 八、路由配置
在 v5 中,通常使用 createBrowserRouter 来创建 router 示例,再把 router 实例作为参数传递给 《RouterProvider router={router} /》
在 v6 中,可以使用 useRoutes 钩子,直接将路由渲染到页面中
`export default function App() {
return (
《div》
《Navbar /》
《Routes》
《Route path="/" element={《Home /》} /》
《Route path="/invoices" element={《Invoices /》}》
《Route path=":id" element={《Invoice /》} /》
《Route path="pending" element={《Pending /》} /》
《Route path="complete" element={《Complete /》} /》
《/Route》
《/Routes》
《/div》
);
}`
`import { useRoutes } from "react-router-dom";
const routes = useRoutes([
{ path: "/", element: 《Home /》 },
{
path: "/invoices",
element: 《Invoices /》,
children: [
{ path: ":id", element: 《Invoice /》 },
{ path: "/pending", element: 《Pending /》 },
{ path: "/complete", element: 《Complete /》 },
],
},
]);
export default function App() {
return (
《div》
《Navbar /》
{routes}
《/div》
);
}`